<?php
/** 
 * 
 *
 * @package api
 * @subpackage collections
 * @author $Author$
 * @version $Id$ 
 */
/**
 * 
 */ 
require_once( "lang/Object.php" );
require_once( "util/Collection.php" );
require_once( "lang/UnsupportedOperationException.php" );
require_once( "lang/NullPointerException.php" );

/**
 * Class AbstractCollection
 *
 * This class provides a skeletal implementation of the Collection interface, to minimize the effort required to implement 
 * this interface.
 *
 * To implement an unmodifiable collection, the programmer needs only to extend this class and provide implementation 
 * for the size methods.
 * 
 * To implement a modifiable collection, the programmer must additionally override this class's add method (which 
 * otherwise throws an UnsupportedOperationException).
 *
 * The programmer should generally provide a void (no argument) constructor, as per the recommendation 
 * in the Collection interface specification.
 * 
 * The documentation for each non-abstract methods in this class describes its implementation in detail. Each of 
 * these methods may be overridden if the collection being implemented admits a more efficient implementation.
 *
 * This class is a member of the PHP Collections Framework. 
 * 
 * @package api
 * @subpackage collections
 * @author $Author$
 * @version $Id$ 
 */
abstract class AbstractCollection extends Object implements Collection {
	
	/**
	 * Sole constructor.  (For invocation by subclass constructors)
	 */
	public function __construct() {
		parent::__construct();
	}
	
	/**
	 * Ensures that this collection contains the specified element.
	 * 
	 * Ensures that this collection contains the specified element (optional operation). Returns true if the collection changed 
	 * as a result of the call. (Returns false if this collection does not permit duplicates and already contains the 
	 * specified element.) Collections that support this operation may place limitations on what elements may be added to 
	 * the collection. In particular, some collections will refuse to add null elements, and others will impose restrictions 
	 * on the type of elements that may be added. Collection classes should clearly specify in their documentation any 
	 * restrictions on what elements may be added.
	 *
	 * @param Object $o element whose presence in this collection is to be ensured.
	 * @returns boolean true if this collection changed as a result of the call
	 * @throws {@link UnsupportedOperationException} - if the add method is not supported by this collection.
	 * @throws {@link ClassCastException} - if the class of the specified element prevents it from being added to 
	 *		this collection.
	 * @throws {@link NullPointerException} - if the specified element is null and this collection does not support 
	 *		null elements.
	 * @throws {@link IllegalArgumentException} - if some aspect of this element prevents it from being added to 
	 *		this collection.
	 */
	public function add( Object $o ) {
		throw new UnsupportedOperationException();
	}
	
	/**
	 * Adds all of the elements in the specified collection to this collection.
	 * 
	 * Adds all of the elements in the specified collection to this collection. The behavior of this operation is undefined if the
	 * specified collection is modified while the operation is in progress. (This implies that the behavior of this call 
	 * is undefined if the specified collection is this collection, and this collection is nonempty.)
	 * 
	 * This implementation iterates over the specified collection, and adds each object returned by the iterator to this 
	 * collection, in turn.
	 *
	 * @param Collection $c elements to be inserted into this collection.
	 * @returns boolean true if this collection changed as a result of the call
	 * @throws {@link UnsupportedOperationException} - if this collection does not support the {@link addAll} function.
	 * @throws {@link ClassCastException} - if the class of an element of the specified collection prevents it from being 
	 		added to this collection
	 * @throws {@link NullPointerException} - if the specified collection contains one ore more null elements and this 
	 		collection does not support null elements, or if the specified collection is null.
	 * @throws {@link IllegalArgumentException} - some aspect of an element of the specified collection prevents it from 
	 		being added to this collection.
	 * @see add()
	 */
	public function addAll( Collection $c ) {
		if (is_null($c))
			throw new NullPointerException();
	
		$iterator = $c->iterator();
		while ( $iterator->hasNext() ) {
			$obj = $iterator->getNext();
			$this->add( $obj );
		}
		return true;
	}
	
	/**
	 * Removes all of the elements from this collection.
	 *
	 * Removes all of the elements from this collection.  This collection will be empty after this method returns unless it 
	 * throws an exception.
	 *
	 * @throws {@link UnsupportedOperationException}- if the {@link clear} method is not supported by this collection.
	 */
	public function clear() {
		$iterator = $this->iterator();
		while ($iterator->hasNext()) {
			$iterator->remove();
		}
	}
	
	/**
	 * Returns true if this collection contains the specified element.
	 *
	 * Returns true if this collection contains the specified element. More formally, returns true if and only if this 
	 * collection contains at least one element e such that (o==null ? e==null : o.equals(e)).
	 *
	 * This implementation iterates over the elements in the collection, checking each element in turn for equality 
	 * with the specified element. 
	 *
	 * @param Object $o object to be checked for containment in this collection.
	 * @returns boolean true if this collection contains the specified element.
	 */
	public function contains( Object $o ) {
		$iterator = $this->iterator();
		while ($iterator->hasNext()) {
			$e = $iterator->getNext();
			if ( $o->equals( $e ) )
				return true;
		}
		return false;
	}
	
	/**
	 * Returns true if this collection contains all of the elements in the specified collection.
	 *
	 * This implementation iterates over the specified collection, checking each element returned by the iterator in 
	 * turn to see if it's contained in this collection. If all elements are so contained true is returned, otherwise false.
	 *
	 * @param Collection $c collection to be checked for containment in this collection.
	 * @returns boolean true if this collection contains all of the elements in the specified collection.
	 * @throws {@link NullPointerException} - if the specified collection is null
	 */
	public function containsAll( Collection $c ) {
		if (is_null($c))
			throw new NullPointerException();
	
		$c_iterator = $c->iterator();
		while ($c_iterator->hasNext()) {
			$object = $c_iterator->getNext();
			if ( !$this->contains( $object ))
				return false;
		}
		return true;
	}
	
	/**
	 * Returns true if this collection contains no elements.
	 * 
	 * This implementation returns {@link size size()} == 0.
	 *
	 * @returns boolean true if this collection contains no elements.
	 */
	public function isEmpty() {
		return ($this->size() == 0);
	}
	
	/**
	 * Removes a single instance of the specified element from this collection, if it is present.
	 * 
	 * Removes a single instance of the specified element from this collection, if it is present. 
	 * More formally, removes an element e such that (o==null ? e==null : o.equals(e)), if the collection contains 
	 * one or more such elements. Returns true if the collection contained the specified element (or equivalently, 
	 * if the collection changed as a result of the call).
	 *
	 * This implementation iterates over the collection looking for the specified element. If it finds the element, 
	 * it removes the element from the collection using the iterator's remove method.
	 *
	 * Note that this implementation throws an UnsupportedOperationException if the iterator returned by this 
	 * collection's iterator method does not implement the remove method and this collection contains the specified object. 
	 *
	 * @param Object $o element to be removed from this collection if present.
	 * @returns boolean true if the collection contained the specified element.
	 * @throws {@link UnsupportedOperationException} - if the remove method is not supported by this collection
	 */	
	public function remove( Object $o ) {
		$iterator = $this->iterator();
		while( $iterator->hasNext() ) {
			$obj = $iterator->getNext();
			if ( $o->equals( $obj ) ) {
				$iterator->remove();
				return true;
			}
		}
		return false;
	}	
	
	/**
	 * Removes from this collection all of its elements that are contained in the specified collection.
	 * 
	 * This implementation iterates over this collection, checking each element returned by the iterator in turn to see 
	 * if it's contained in the specified collection. If it's so contained, it's removed from this collection with the 
	 * iterator's remove method.
	 *
	 * Note that this implementation will throw an UnsupportedOperationException if the iterator returned by the 
	 * iterator method does not implement the remove method and this collection contains one or more elements in 
	 * common with the specified collection.
	 *
	 * @param Collection $c elements to be removed from this collection
	 * @returns boolean true if the collection changed as a result of this call
	 * @throws {@link UnsupportedOperationException} - if the removeAll method is not supported by this collection
	 * @throws {@link NullPointerException} - if the specified collection is null.
	 * @see remove(), contains()
	 */	
	public function removeAll( Collection $c ) {
		if (is_null($c))
			throw new NullPointerException();
		
		$return_value = false;
		
		$iterator = $this->iterator();
		while ($iterator->hasNext() ) {
			$next = $iterator->getNext();
			if ( $c->contains( $next )) {
				$return_value = true;
				$iterator->remove();
			}
		}
		return $return_value;
	
	}
	
	/**
	 * Retains only the elements in this collection that are contained in the specified collection (optional operation).
	 * 
	 * Retains only the elements in this collection that are contained in the specified collection (optional operation). 
	 * In other words, removes from this collection all of its elements that are not contained in the specified collection.
	 *
	 * This implementation iterates over this collection, checking each element returned by the iterator in turn 
	 * to see if it's contained in the specified collection. If it's not so contained, it's removed from this collection 
	 * with the iterator's remove method.
	 *
	 * Note that this implementation will throw an UnsupportedOperationException if the iterator returned by the 
	 * iterator method does not implement the remove method and this collection contains one or more elements not present 
	 * in the specified collection.
	 *
	 * @param Collection $celements to be retained in this collection.
	 * @returns boolean true if the collection changed as a result of this call
	 * @throws {@link UnsupportedOperationException} - if the retainAll method is not supported by this collection
	 * @throws {@link NullPointerException} - if the specified collection is null.
	 * @see remove(), contains()
	 */	
	public function retainAll( Collection $c ) {
		if (is_null($c))
			throw new NullPointerException();
		
		$return_value = false;
		
		$iterator = $this->iterator();
		while ($iterator->hasNext() ) {
			$next = $iterator->getNext();
			if ( !$c->contains( $next )) {
				$return_value = true;
				$iterator->remove();
			}
		}
		return $return_value;
	}
		
	/**
	 * Returns an array containing all of the elements in this collection. 
	 *
	 * If the collection makes any guarantees as to what order its elements are returned by its iterator, this method 
	 * must return the elements in the same order.
	 *
	 * This implementation allocates the array to be returned, and iterates over the elements in the collection, 
	 * storing each object reference in the next consecutive element of the array, starting with element 0.
	 * 
	 * This method acts as bridge between array-based and collection-based APIs. 
	 * 
	 * @returns array an array containing all of the elements in this collection
	 */
	public function toArray() {
		$objects = array();
		
		$iterator = $this->iterator();
		while ($iterator->hasNext()) {
			$next = $iterator->getNext();
			$objects[] = $next;
		}
		return $objects;
	}
		
}

?>
